package com.warrior.superdata.util;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;

/**
 * @ClassName: BeanUtils
 * @Description:(实体类赋值方法)
 * @author: xujian
 * @date: 2017年10月31日 下午2:46:58
 * @Copyright: 2017
 */
@Slf4j
public class BeanUtils {

    /**
     * @Title: toBean
     * @Description: (反射实体类赋值targetMap里面可以互相转化的字段对应关系)
     * @param @param filterBean
     * @param @param targetBean
     * @param @param paramMap
     * @param @throws Exception    参数
     * @author xujian
     * @return void    返回类型
     * @throws
     */
	/*@SuppressWarnings("rawtypes")
	public static void toBean(Object filterBean, Object targetBean, Map<String, String> paramMap) throws Exception {
		Class filterClass = Class.forName(filterBean.getClass().getName());
		Class targetClass = Class.forName(targetBean.getClass().getName());
		Field[] fields1 = filterClass.getDeclaredFields();
		Field[] fields2 = targetClass.getDeclaredFields();
		for (Field f1 : fields1) {
			Object value = invokeGetMethod(filterBean, f1.getName(), null);
			for (Field f2 : fields2) {
				String f1GetName = paramMap.get(f1.getName());

				if (StringUtils.isNotBlank(f1GetName)) {
					if (f1GetName.equals(f2.getName())) {
						Object[] obj = new Object[1];
						obj[0] = value;
						if ("class java.util.Date".equals(f2.getType().toString())) {
							Object[] obj2 = new Object[1];
							obj2[0] = DateUtil.convertStringToDate((String) value, CommonStatus.CONSTANT_DATE_FORMAT);
							invokeSetMethod(targetBean, f2.getName(), obj2);
							continue;
						}
						invokeSetMethod(targetBean, f2.getName(), obj);
					}
				} else {
					if (f1.getName().equals(f2.getName())) {
						Object[] obj = new Object[1];
						obj[0] = value;
						if ("class java.util.Date".equals(f2.getType().toString())
								&& "class java.lang.String".equals(f1.getType().toString())) {
							Object[] obj2 = new Object[1];
							obj2[0] = DateUtil.convertStringToDate((String) value, CommonStatus.CONSTANT_DATE_FORMAT);
							invokeSetMethod(targetBean, f2.getName(), obj2);
							continue;
						}
						if ("class java.util.Date".equals(f1.getType().toString())
								&& "class java.lang.String".equals(f2.getType().toString())) {
							Object[] obj2 = new Object[1];
							obj2[0] = DateUtil.convertDateToString((Date) value, CommonStatus.CONSTANT_DATE_FORMAT);
							invokeSetMethod(targetBean, f2.getName(), obj2);
							continue;
						}
						invokeSetMethod(targetBean, f2.getName(), obj);
					}
				}
			}
		}
	}*/

    /**
     * @Title: invokeGetMethod
     * @Description: (执行某个Field的getField方法)
     * @param @param filterBean
     * @param @param fieldName
     * @param @param args
     * @param @return    参数
     * @author xujian
     * @return Object    返回类型
     * @throws
     */
    public static Object invokeGetMethod(Object filterBean, String fieldName, Object... args) {
        String methodName = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
        Method method = null;
        try {
            Class[] parameterTypes = new Class[1];
            Class targetClass = Class.forName(filterBean.getClass().getName());
            Field field = null;
            Boolean isParentFiled = false;
            Class parentClass = null;
            try {
                field = targetClass.getDeclaredField(fieldName);
            } catch (Exception e) {
                log.warn("【{}未找到{}字段，去父类找】", targetClass.getName(), fieldName);
                Class tempClass = targetClass;
                while (tempClass != null) {
                    Field[] declaredFields = tempClass.getDeclaredFields();
                    for (Field fieldItem : declaredFields) {
                        if (fieldName.equals(fieldItem.getName())) {
                            field = fieldItem;
                            isParentFiled = true;
                            parentClass = tempClass;
                            break;
                        }
                    }
                    tempClass = tempClass.getSuperclass();
                }
            }
            parameterTypes[0] = field.getType();
            if (isParentFiled && null != parentClass) {
                method = parentClass.getDeclaredMethod("get" + methodName);
            } else {
                method = targetClass.getDeclaredMethod("get" + methodName);
            }
            return method.invoke(filterBean, args);
        } catch (Exception e) {
            log.error("【invokeGetMethod异常 errMsg:{}】", e.getMessage());
        }
        return null;
    }

    /**
     * @Author xujian
     * @Description 执行对象的某个方法
     * @Date 16:31 2021/3/23
     * @Param [bean, aClass, methodName, paramTypes, args]
     * bean 对象， aClass 对象的Class，methodName 执行的方法名称，paramTypes 参数名称，args 具体参数
     * @return java.lang.Object
     **/
    public static Object invokeGetMethod(Object bean, Class aClass, String methodName, Class paramTypes, Object... args) {
        Method method = null;
        try {
            method = aClass.getDeclaredMethod(methodName, paramTypes);
            return method.invoke(bean, args);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return method;
    }

    /**
     * @Title: invokeSetMethod
     * @Description: (执行某个Field的setField方法)
     * @param @param targetBean
     * @param @param fieldName
     * @param @param args    参数
     * @author xujian
     * @return void    返回类型
     * @throws
     */
    public static void invokeSetMethod(Object targetBean, String fieldName, Object... args) {
        String methodName = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
        Method method = null;
        try {
            Class[] parameterTypes = new Class[1];
            Class targetClass = Class.forName(targetBean.getClass().getName());
            Field field = null;
            Boolean isParentFiled = false;
            Class parentClass = null;
            try {
                field = targetClass.getDeclaredField(fieldName);
            } catch (Exception e) {
                log.warn("【{}未找到{}字段，去父类找】", targetClass.getName(), fieldName);
                Class tempClass = targetClass;
                while (tempClass != null) {
                    Field[] declaredFields = tempClass.getDeclaredFields();
                    for (Field fieldItem : declaredFields) {
                        if (fieldName.equals(fieldItem.getName())) {
                            field = fieldItem;
                            isParentFiled = true;
                            parentClass = tempClass;
                            break;
                        }
                    }
                    tempClass = tempClass.getSuperclass();
                }
            }

            parameterTypes[0] = field.getType();
            if (isParentFiled && null != parentClass) {
                method = parentClass.getDeclaredMethod("set" + methodName, parameterTypes);
            } else {
                method = targetClass.getDeclaredMethod("set" + methodName, parameterTypes);
            }
            if (null == args) {
                if (parameterTypes[0].getName().equals("java.lang.String")) {
                    method.invoke(targetBean, "");
                }
                if (parameterTypes[0].getName().equals("java.util.List")) {
                    method.invoke(targetBean, new ArrayList());
                }
            } else {
                method.invoke(targetBean, args);
            }
        } catch (Exception e) {
            log.error("【invokeSetMethod异常 errMsg:{}】", e.getMessage());
        }
    }

    /**
     * @Title: invokeExampleEqualToSetMethod
     * @Description: (执行某个Field的andFieldEqualTo方法)
     * @param @param targetBean
     * @param @param fieldName
     * @param @param args    参数
     * @author xujian
     * @return void    返回类型
     * @throws
     */
    private static void invokeExampleEqualToSetMethod(Object targetBean, Field field, Object[] args) {
        String fieldName = field.getName();
        String methodName = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
        Method method = null;
        try {
            Class[] parameterTypes = new Class[1];
            Class targetClass = Class.forName(targetBean.getClass().getName());
            parameterTypes[0] = field.getType();
            method = targetClass.getMethod("and" + methodName + "EqualTo", parameterTypes);
            method.invoke(targetBean, args);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 将JSONObject转换成相应的实体工具类
     * @param bean
     * @param obj
     * @return 该实体类Object
     * @throws Exception
     * @author 叶森
     * @time 2018-01-27
     */
    public static <T> T convertBeamByJSONObject(T bean, JSONObject obj) throws Exception {
        Class<?> c = Class.forName(bean.getClass().getName());
        Field[] field = c.getDeclaredFields();
        Object object = c.newInstance();
        for (Field f : field) {
            String name = f.getName();
            String val = JsonUtil.getString(name, obj);
            String methodStr = "set" + name.toUpperCase().substring(0, 1) + name.substring(1);
            Method method = c.getMethod(methodStr, new Class[]{f.getType()});
            if ("String".equals(f.getType().getSimpleName())) {
                method.invoke(object, val);
            } else if ("Integer".equals(f.getType().getSimpleName())) {
                method.invoke(object, Integer.parseInt(val));
            }
        }
        return (T) object;
    }

    /**
     * 实体类转换成example类（全是EqualTo条件）
     * @param filterBean
     * @param targetBean
     * @author xujian
     */
    public static void toBeanExampleEqualTo(Object filterBean, Object targetBean) {
        try {
            Class filterClass = Class.forName(filterBean.getClass().getName());
            Field[] fields1 = filterClass.getDeclaredFields();
            for (Field f1 : fields1) {
                Object value = invokeGetMethod(filterBean, f1.getName(), null);
                if (null != value) {
                    Object[] obj = new Object[1];
                    obj[0] = value;
                    invokeExampleEqualToSetMethod(targetBean, f1, obj);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
